package com.hmall.order.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.common.client.ItemClient;
import com.hmall.common.client.UserClient;
import com.hmall.common.pojo.Address;
import com.hmall.common.pojo.Item;
import com.hmall.order.dto.OrderDTO;
import com.hmall.order.mapper.OrderDetailMapper;
import com.hmall.order.mapper.OrderLogisticsMapper;
import com.hmall.order.mapper.OrderMapper;
import com.hmall.order.pojo.Order;
import com.hmall.order.pojo.OrderDetail;
import com.hmall.order.pojo.OrderLogistics;
import com.hmall.order.service.IOrderService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.UUID;

@Service
@Slf4j
@RequiredArgsConstructor //减少注入
public class OrderService extends ServiceImpl<OrderMapper, Order> implements IOrderService {
    ThreadLocal<Object> userThreadLocal = new ThreadLocal<>();

    private final ItemClient itemClient;
    private final OrderDetailMapper orderDetailMapper;
    private final UserClient userClient;
    private final OrderLogisticsMapper orderLogisticsMapper;
    private final Snowflake snowflake = new Snowflake();
    private final RabbitTemplate rabbitTemplate;

    @Transactional(rollbackFor = Exception.class)
    public Long createOrder(OrderDTO orderDTO) {
        Date now = Date.from(LocalDateTime.now().toInstant(ZoneOffset.UTC));

        long orderId = snowflake.nextId();
        Item item = itemClient.getItemById(orderDTO.getItemId());
        Long totalFee = orderDTO.getNum() * item.getPrice();
        Order order = Order.builder()
                .id(orderId)
                .totalFee(totalFee)
                .paymentType(3)
                .userId(2L)
                .status(1)
                .createTime(now)
                .build();
        save(order);

        OrderDetail orderDetail = OrderDetail.builder()
                .orderId(orderId)
                .itemId(item.getId())
                .num(orderDTO.getNum())
                .title(item.getName())
                .spec(item.getSpec())
                .price(item.getPrice())
                .image(item.getImage())
                .createTime(now)
                .updateTime(now)
                .build();
        //1,将orderDetail存入数据库
        orderDetailMapper.insert(orderDetail);
        Address address = userClient.findAddressById(orderDTO.getAddressId());
        //2,将orderLogistics存入数据库
        OrderLogistics orderLogistics = OrderLogistics.builder()
                .orderId(orderId)
                .logisticsNumber("ZT123456789")
                .logisticsCompany("ZT")
                .contact("张三")
                .phone("13212345678")
                .province(address.getProvince())
                .city(address.getCity())
                .town(address.getTown())
                .street(address.getStreet())
                .createTime(now)
                .updateTime(now)
                .build();
        orderLogisticsMapper.insert(orderLogistics);

        //3,扣减库存
        itemClient.deductStock(orderDTO.getItemId(), orderDTO.getNum());
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());//消息唯一id
        //4,开启生产者发送确认
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                if (ack) {
                    log.info("订单id发送到交换机成功，订单id：{}", orderId);
                } else {
                    log.error("订单id发送到交换机失败，原因：{}", cause);
                }
            }
        });
        //5,失败回执
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
                if ("hmall.delay.exchange".equals(exchange)) {
                    return;
                }
                log.error("交换机转发订单id到队列失败，失败原因：{}，原始消息：{}，响应状态码：{}，交换机：{}，路由key：{}", replyText, new String(message.getBody()), replyCode, exchange, routingKey);
            }
        });
        Message message = MessageBuilder.withBody(String.valueOf(orderId).getBytes()).setHeader("x-delay", "1800000").build();
        rabbitTemplate.convertAndSend("hmall.delay.exchange", "hmall.overdue.order", message, correlationData);
        return orderId;
    }

}

